import requests
import lark_oapi as lark
from lark_oapi.api.sheets.v3 import QuerySpreadsheetSheetRequest
from typing import List, Dict, Optional
import re

class FeishuSheet:
    def __init__(self, app_id: str = "", app_secret: str = ""):
        self.app_id = app_id
        self.app_secret = app_secret
        self.access_token = None
        self.base_api_url = "https://open.feishu.cn/open-apis"
        self.SPREADSHEET_TOKEN_PATTERN = re.compile(r'[a-zA-Z0-9]{28,36}')
        self.SHEET_ID_PATTERN = re.compile(r'^[a-zA-Z0-9_-]{6,10}$')

    def get_access_token(self) -> Optional[str]:
        url = f"{self.base_api_url}/auth/v3/tenant_access_token/internal/"
        params = {"app_id": self.app_id, "app_secret": self.app_secret}
        try:
            response = requests.post(url, json=params, timeout=10)
            response.raise_for_status()
            result = response.json()
            if result.get("code") == 0:
                self.access_token = result["tenant_access_token"]
                return self.access_token
            else:
                print(f"飞书令牌获取失败，错误码：{result.get('code')}，信息：{result.get('msg')}")
                return None
        except requests.exceptions.RequestException as e:
            print(f"飞书令牌请求失败：{str(e)}")
            return None

    def get_sheet_ids(self, spreadsheet_token: str) -> List[Dict]:
        client = lark.Client.builder().app_id(self.app_id).app_secret(self.app_secret).log_level(lark.LogLevel.DEBUG).build()
        request = QuerySpreadsheetSheetRequest.builder().spreadsheet_token(spreadsheet_token).build()
        response = client.sheets.v3.spreadsheet_sheet.query(request)
        if not response.success():
            print(f"获取工作表信息失败: {response.code}, {response.msg}")
            return []
        sheets_info = []
        if response.data and hasattr(response.data, 'sheets'):
            for sheet in response.data.sheets:
                if hasattr(sheet, 'sheet_id'):
                    sheets_info.append({"sheet_id": sheet.sheet_id, "title": getattr(sheet, 'title', '')})
        return sheets_info

    def get_cell_value(self, spreadsheet_token: str, sheet_id: str, cell_range: str) -> Optional[str]:
        access_token = self.get_access_token()
        if not access_token:
            print("无法获取飞书访问令牌")
            return None
        full_range = f"{sheet_id}!{cell_range}" if ":" in cell_range else f"{sheet_id}!{cell_range}:{cell_range}"
        url = f"{self.base_api_url}/sheets/v2/spreadsheets/{spreadsheet_token}/values/{full_range}"
        headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
        try:
            response = requests.get(url, headers=headers, timeout=10)
            response.raise_for_status()
            result = response.json()
            if result.get("code") == 0:
                values = result.get("data", {}).get("valueRange", {}).get("values", [])
                return values[0][0] if (values and len(values) > 0 and len(values[0]) > 0) else ""
            else:
                print(f"获取单元格值失败，错误码：{result.get('code')}，信息：{result.get('msg')}")
                return None
        except requests.exceptions.RequestException as e:
            print(f"获取单元格值请求失败：{str(e)}")
            return None

    def update_cell_value(self, spreadsheet_token: str, sheet_id: str, cell_range: str, value: str) -> bool:
        access_token = self.get_access_token()
        if not access_token:
            print("无法获取飞书访问令牌")
            return False
        full_range = f"{sheet_id}!{cell_range}" if ":" in cell_range else f"{sheet_id}!{cell_range}:{cell_range}"
        url = f"{self.base_api_url}/sheets/v2/spreadsheets/{spreadsheet_token}/values"
        headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
        data = {"valueRange": {"range": full_range, "values": [[value]]}}
        try:
            response = requests.put(url, headers=headers, json=data, timeout=10)
            response.raise_for_status()
            return response.json().get("code") == 0
        except requests.exceptions.RequestException as e:
            print(f"更新单元格值请求失败：{str(e)}")
            return False